package com.seed.core.configuration;

import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.seed.core.action.Action;
import com.seed.core.column.Column;
import com.seed.core.configuration.relation.BelongsToConfiguration;
import com.seed.core.configuration.relation.HabtmConfiguration;
import com.seed.core.configuration.relation.HasManyConfiguration;
import com.seed.core.configuration.relation.HasOneConfiguration;
import com.seed.core.converter.ActionConverter;
import com.seed.core.converter.ColumnConverter;
import com.seed.core.enumeration.SeedType;
import com.seed.core.listener.OnSaveListener;
import com.seed.core.listener.OnSetListener;
import com.seed.core.listener.OnUpdateListener;
import com.seed.core.pojo.seed.*;
import com.seed.util.StrKit;

import java.util.*;

@JsonInclude(JsonInclude.Include.NON_NULL)
public class SeedConfiguration extends HomeConfiguration {
    private String tableName;
    private String tableSchema;
    private SeedType type;
    private String nameColumn; // 一般是name字段

    private LinkedHashMap<String, ColumnConfiguration1> columns; // 列定义， 键为列名, 下划线风格
    private LinkedHashMap<String, ActionConfiguration1> actions;
    private LinkedHashMap<String, HasOneConfiguration> hasOne; // 主子： 一对一关系， 键为cross, 下划线风格
    private LinkedHashMap<String, HasManyConfiguration> hasMany; // 主子： 一对多关系， 键为cross, 下划线风格
    private LinkedHashMap<String, BelongsToConfiguration> belongsTo; // 子主： 一对一关系， 键为cross, 下划线风格
    private LinkedHashMap<String, HabtmConfiguration> habtm; // 平级： 多对多关系， 键为cross, 下划线风格

    private String onSave; // 保存时的事件监听
    private String onUpdate; // 更新时的事件监听
    private String onSet; // 查询时的事件监听

    private String[] declares; // 功能所需要的数据列
    private String[] searches; // 如果是功能是page或list，这里申明对应的搜索拦，形如：name_like,age_eq等
    private String[] orders; // 排序
    private Map<String, StatConfiguration> stats; // 统计
    private Map<String, GroupConfiguration> groups; // 对【declare】进行分组

    private Boolean checkLogin; // 是否需要检查登录
    private Boolean checkAction; // 是否需要检查功能权限

    public Seed toSeed() {
        Seed ret = new Seed();
        ret.setTableName(tableName);
        ret.setTableSchema(tableSchema);
        ret.setType(type);
        ret.setLabel(label);
        ret.setComment(comment);
        ret.setNameColumn(nameColumn);

        if(this.columns != null) {
            LinkedHashMap<String, Column> columns = new LinkedHashMap<>();
            for (Map.Entry<String, ColumnConfiguration1> entry: this.columns.entrySet()) {
                String columnName = entry.getKey();
                Column column = ColumnConverter.toColumn(entry.getValue());
                column.setName(columnName);
                columns.put(columnName, column);
            }
            ret.setColumns(columns);
        }

        if(this.actions != null) {
            Map<String, Action> actions = new HashMap<>();
            for (Map.Entry<String, ActionConfiguration1> entry: this.actions.entrySet()) {
                String actionName = entry.getKey();
                Action action = ActionConverter.toAction(entry.getValue());
                action.setName(actionName);
                actions.put(actionName, action);
            }
            ret.setActions(actions);
        }

        LinkedHashMap<String, Relation> relations = new LinkedHashMap<>();
        if(this.hasOne != null) {
            for (Map.Entry<String, HasOneConfiguration> entry: this.hasOne.entrySet()) {
                relations.put(entry.getKey(), entry.getValue().toHasOne());
            }
        }
        if(this.belongsTo != null) {
            for (Map.Entry<String, BelongsToConfiguration> entry: this.belongsTo.entrySet()) {
                relations.put(entry.getKey(), entry.getValue().toBelongsTo());
            }
        }
        if(this.hasMany != null) {
            for (Map.Entry<String, HasManyConfiguration> entry: this.hasMany.entrySet()) {
                relations.put(entry.getKey(), entry.getValue().toHasMany());
            }
        }
        if(this.habtm != null) {
            for (Map.Entry<String, HabtmConfiguration> entry: this.habtm.entrySet()) {
                relations.put(entry.getKey(), entry.getValue().toHabtm());
            }
        }
        ret.setRelations(relations);

        if(StrUtil.isNotBlank(this.onSave)) {
            List<? extends OnSaveListener> onSave = new ArrayList<>();
            for(String className: this.onSave.split(",")) {
                onSave.add(ReflectUtil.newInstance(className.trim()));
            }
            ret.setOnSave(onSave);
        }
        if(StrUtil.isNotBlank(this.onUpdate)) {
            List<? extends OnUpdateListener> onUpdate = new ArrayList<>();
            for(String className: this.onUpdate.split(",")) {
                onUpdate.add(ReflectUtil.newInstance(className.trim()));
            }
            ret.setOnUpdate(onUpdate);
        }
        if(StrUtil.isNotBlank(this.onSet)) {
            List<? extends OnSetListener> onSet = new ArrayList<>();
            for(String className: this.onSet.split(",")) {
                onSet.add(ReflectUtil.newInstance(className.trim()));
            }
            ret.setOnSet(onSet);
        }

        if(declares != null) ret.setDeclares(List.of(declares));
        if(searches != null) ret.setSearches(List.of(searches));
        if(orders != null) ret.setOrders(List.of(orders));

        if(stats != null) {
            Map<String, Stat> statMap = new HashMap<>();
            for(Map.Entry<String, StatConfiguration> entry: stats.entrySet()) {
                StatConfiguration statConfiguration = entry.getValue();
                Stat stat = new Stat();
                stat.setName(entry.getKey());
                stat.setType(statConfiguration.getType());
                stat.setDeclare(statConfiguration.getDeclare());
                stat.setSearches(statConfiguration.getSearches());
                statMap.put(entry.getKey(), stat);
            }
            ret.setStats(statMap);
        }

        ret.setCheckLogin(checkLogin);
        ret.setCheckAction(checkAction);

        return ret;
    }

    public SeedConfiguration toFront() {
        SeedConfiguration ret = new SeedConfiguration();
        ret.setType(type);
        ret.setNameColumn(nameColumn);

        ret.setColumns(columns);
        if(actions != null) {
            LinkedHashMap<String, ActionConfiguration1> frontActions = new LinkedHashMap<>();
            for(Map.Entry<String, ActionConfiguration1> entry: actions.entrySet()) {
                frontActions.put(entry.getKey(), ActionConverter.toFront(entry.getValue()));
            }
            ret.setActions(frontActions);
        }

        if(hasOne != null) {
            LinkedHashMap<String, HasOneConfiguration> frontHasOne = new LinkedHashMap<>();
            for(Map.Entry<String, HasOneConfiguration> entry: hasOne.entrySet()) {
                frontHasOne.put(entry.getKey(), entry.getValue().toFront());
            }
            ret.setHasOne(frontHasOne);
        }

        if(belongsTo != null) {
            LinkedHashMap<String, BelongsToConfiguration> frontBelongsTo = new LinkedHashMap<>();
            for(Map.Entry<String, BelongsToConfiguration> entry: belongsTo.entrySet()) {
                frontBelongsTo.put(entry.getKey(), entry.getValue().toFront());
            }
            ret.setBelongsTo(frontBelongsTo);
        }

        if(hasMany != null) {
            LinkedHashMap<String, HasManyConfiguration> frontHasMany = new LinkedHashMap<>();
            for(Map.Entry<String, HasManyConfiguration> entry: hasMany.entrySet()) {
                frontHasMany.put(entry.getKey(), entry.getValue().toFront());
            }
            ret.setHasMany(frontHasMany);
        }

        if(habtm != null) {
            LinkedHashMap<String, HabtmConfiguration> frontHabtm = new LinkedHashMap<>();
            for(Map.Entry<String, HabtmConfiguration> entry: habtm.entrySet()) {
                frontHabtm.put(entry.getKey(), entry.getValue().toFront());
            }
            ret.setHabtm(frontHabtm);
        }

        ret.setDeclares(declares);
        if(searches != null) {
            List<String> frontSearches = new ArrayList<>();
            for(String search: searches) {
                String[] items = StrKit.cutInTwo(search, '=', false);
                if(StrUtil.isBlank(items[1])) frontSearches.add(search);
            }
            ret.setSearches(frontSearches.toArray(new String[0]));
        }
        if(orders != null) {
            List<String> frontOrders = new ArrayList<>();
            for(String order: orders) {
                String[] items = StrKit.cutInTwo(order, '=', false);
                if(StrUtil.isBlank(items[1])) frontOrders.add(order);
            }
            ret.setOrders(frontOrders.toArray(new String[0]));
        }

        ret.setStats(stats);
        ret.setGroups(groups);
        ret.setCheckLogin(checkLogin);
        ret.setCheckAction(checkAction);

        ret.setMode(mode);
        ret.setLabel(label);
        ret.setComment(comment);
        ret.setComponent(component);
        ret.setLayout(layout);
        ret.setComponentProps(componentProps);
        ret.setIcon(icon);
        ret.setColor(color);
        ret.setSize(size);
        ret.setHoverColor(hoverColor);
        ret.setAffix(affix);
        ret.setHidden(hidden);
        ret.setBreadcrumb(breadcrumb);
        ret.setNoTagsView(noTagsView);

        return ret;
    }

    public String getTableName() {
        return tableName;
    }

    public void setTableName(String tableName) {
        this.tableName = tableName;
    }

    public String getTableSchema() {
        return tableSchema;
    }

    public void setTableSchema(String tableSchema) {
        this.tableSchema = tableSchema;
    }

    public SeedType getType() {
        return type;
    }

    public void setType(SeedType type) {
        this.type = type;
    }

    public String getNameColumn() {
        return nameColumn;
    }

    public void setNameColumn(String nameColumn) {
        this.nameColumn = nameColumn;
    }

    public LinkedHashMap<String, ColumnConfiguration1> getColumns() {
        return columns;
    }

    public void setColumns(LinkedHashMap<String, ColumnConfiguration1> columns) {
        this.columns = columns;
    }

    public Map<String, ActionConfiguration1> getActions() {
        return actions;
    }

    public void setActions(LinkedHashMap<String, ActionConfiguration1> actions) {
        this.actions = actions;
    }

    public LinkedHashMap<String, HasOneConfiguration> getHasOne() {
        return hasOne;
    }

    public void setHasOne(LinkedHashMap<String, HasOneConfiguration> hasOne) {
        this.hasOne = hasOne;
    }

    public LinkedHashMap<String, HasManyConfiguration> getHasMany() {
        return hasMany;
    }

    public void setHasMany(LinkedHashMap<String, HasManyConfiguration> hasMany) {
        this.hasMany = hasMany;
    }

    public LinkedHashMap<String, BelongsToConfiguration> getBelongsTo() {
        return belongsTo;
    }

    public void setBelongsTo(LinkedHashMap<String, BelongsToConfiguration> belongsTo) {
        this.belongsTo = belongsTo;
    }

    public LinkedHashMap<String, HabtmConfiguration> getHabtm() {
        return habtm;
    }

    public void setHabtm(LinkedHashMap<String, HabtmConfiguration> habtm) {
        this.habtm = habtm;
    }

    public String getOnSave() {
        return onSave;
    }

    public void setOnSave(String onSave) {
        this.onSave = onSave;
    }

    public String getOnUpdate() {
        return onUpdate;
    }

    public void setOnUpdate(String onUpdate) {
        this.onUpdate = onUpdate;
    }

    public String getOnSet() {
        return onSet;
    }

    public void setOnSet(String onSet) {
        this.onSet = onSet;
    }

    public String[] getDeclares() {
        return declares;
    }

    public void setDeclares(String[] declares) {
        this.declares = declares;
    }

    public String[] getSearches() {
        return searches;
    }

    public void setSearches(String[] searches) {
        this.searches = searches;
    }

    public String[] getOrders() {
        return orders;
    }

    public void setOrders(String[] orders) {
        this.orders = orders;
    }

    public Map<String, StatConfiguration> getStats() {
        return stats;
    }

    public void setStats(Map<String, StatConfiguration> stats) {
        this.stats = stats;
    }

    public Map<String, GroupConfiguration> getGroups() {
        return groups;
    }

    public void setGroups(Map<String, GroupConfiguration> groups) {
        this.groups = groups;
    }

    public Boolean getCheckLogin() {
        return checkLogin;
    }

    public void setCheckLogin(Boolean checkLogin) {
        this.checkLogin = checkLogin;
    }

    public Boolean getCheckAction() {
        return checkAction;
    }

    public void setCheckAction(Boolean checkAction) {
        this.checkAction = checkAction;
    }
}
